//
//  WebView.swift
//  BookNew
//
//  Created by iMac on 2021/7/22.
//  Copyright © 2021 iMac. All rights reserved.
//

import Combine
import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    
    class WebModel: ObservableObject {
        @Published var contentText: String = ""
        
        let next = PassthroughSubject<Void, Never>()
        
        func nextAction() {
            next.send()
        }
    }
    @StateObject var model: WebModel
    
    @Binding var urlString: String
    
    @Binding var isRead: Bool
    
    let web: WKWebView = WKWebView()
    
    private let supportWebList = [
        "https://m.biquduu.com/":
            """
        document.getElementById("pb_next").click()
        """,
        "https://m.booktxt.net/":
            """
        document.getElementById("pt_next").click()
        """,
        "https://m.80xs.la/":
            """
        document.getElementById("pt_next").click()
        """,
    ]
    
    func makeUIView(context: Context) -> WKWebView {
        let view = web
        
        
        let blockStr = """
                [
                    {
                        "trigger":{
                            "url-filter":".*",
                            "if-domain":[
                                %@
                            ],
                            "load-type": ["third-party"]
                        },
                        "action":{
                            "type": "block"
                        }
                    }
                ]
                """
        
        let domainString = supportWebList.keys.map({"\""+($0.split(separator: "/").last ?? "")+"\""}) .joined(separator: ",")
        
//        let jsonString = String(format: blockStr, domainString)
        
        let jsonString = ""
        
        WKContentRuleListStore.default()?.compileContentRuleList(forIdentifier: "adv_block", encodedContentRuleList: jsonString, completionHandler: { (list, error) in
            
            guard let contentRuleList = list else {
                print(error as Any)
                return
            }
            let configuration = view.configuration
            configuration.userContentController.add(contentRuleList)
            
        })
        
        view.navigationDelegate = context.coordinator
        view.uiDelegate = context.coordinator
        return view
    }
    
    func updateUIView(_ webView: WKWebView, context: Context) {
        print("WebView \(#function)")
        print("\(isRead)  \(urlString)")
        if isRead, self.model.contentText == ""{
            context.coordinator.getHtmlContent()
        } else {
            if self.model.contentText != "" {
                self.model.contentText = ""
            }
            if let url = URL(string: urlString), context.coordinator.lastUrlString != urlString {
                context.coordinator.lastUrlString = urlString
                let request = URLRequest(url: url)
                webView.load(request)
            }
        }
    }
    
    func makeCoordinator() -> Coordinator {
        print("WebView \(#function)")
        return Coordinator(model: model, view: self)
    }
    
    class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {
        
        let model: WebModel
        let view: WebView
        
        var lastUrlString: String?
        
        var sub : AnyCancellable?
        
        init(model: WebModel, view: WebView) {
            self.model = model
            self.view = view
            
            super.init()
            
            sub = model.next.sink { [unowned self] in
                // 请求下一页
                print("WebView next")
                self.nextPage()
            }
        }
        
        deinit {
            print("WebView Coordinator \(#function)")
            sub?.cancel()
        }
        
        func getHtmlContent() {
            print("WebView getHtmlContent")
            let getHtml_js = "document.documentElement.innerHTML"

            view.web.evaluateJavaScript(getHtml_js) { [unowned self] (html, error) in
                let text = self.dealHtmlStr(host: self.view.urlString, html: (html as? String) ?? "")
                self.model.contentText = (self.model.contentText) + text
            }
            
        }
        
        private func dealHtmlStr(host: String, html: String) -> String {
//            print("\(html)")
            // 逐一测试规则
            let regular1 = re.compile("<div\\sid=\"chaptercontent\"\\sclass=\"Readarea\\sReadAjax_content\"\\sstyle=\"font-size:\\s20px;\">(.*?)</div>", flags: .dotMatchesLineSeparators)
            if let matches = regular1.search(html) {
                var text = matches.group(1)!
                text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
                text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
                let re_p = re.compile("<p.*?</p>", flags: .dotMatchesLineSeparators)
                text = re_p.sub("\n\n\n", text)
                text = (text as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
                text = "\n\n    " + text + "\n\n====================="
                
                return text
            }
            
            let regular2 = re.compile("<div\\sid=\"novelcontent\"\\sclass=\"novelcontent\">(.*?)</div>", flags: .dotMatchesLineSeparators)
            if let matches = regular2.search(html) {
                var text = matches.group(1)!
                text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
                text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
                let re_p = re.compile("<p>(.*?)</p>", flags: .dotMatchesLineSeparators)
                text = re_p.search(text)?.group(1) ?? ""
                text = (text as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
                text = "\n\n    " + text + "\n\n====================="
                
                return text
            }
            
            let regular3 = re.compile("<div\\sid=\"nr1\">(.*?)</div>", flags: .dotMatchesLineSeparators)
            if let matches = regular3.search(html) {
                var text = matches.group(1)!
                text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
                text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
                text = (text as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
                text = "\n\n    " + text + "\n\n====================="
                
                return text
            }
            
            
            return ""
        }
        
        
        private func nextPage() {
            print("WebView nextPage")
            let js = """
                        var a = document.getElementById("pb_next");
                        if (a == null) {
                            a = document.getElementById("pt_next");
                        }
                        if (a != null) {
                            a.click();
                        }
                """
            view.web.evaluateJavaScript(js, completionHandler: nil)
        }
        
        //MARK: - WKNavigationDelegate
        
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            print("\(#function)")
            print("\(String(describing: navigationAction.request.url?.absoluteString))")
            
            decisionHandler(.allow)
        }
        
        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
            print("error -- \(error)")
        }
        
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            print("\(#function)")
            if view.isRead {
               getHtmlContent()
            }
        }
        
        func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
            print("\(#function)")
            print("load url -- \(String(describing: webView.url))")
            
            let url = webView.url?.absoluteString ?? ""
            if view.urlString != url {
                view.urlString = url
                lastUrlString = url
            }
        }
        
        //MARK: - WKUIDelegate
        func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
            print("\(#function)")
            if navigationAction.targetFrame == nil || !navigationAction.targetFrame!.isMainFrame {
                webView.load(navigationAction.request)
            }
            return nil
        }
    }
    
    
    
}

struct WebView_Previews: PreviewProvider {
    @State static var url: String = ""
    @State static var mode: Bool = false
    
    static var previews: some View {
        WebView(model: WebView.WebModel(), urlString: $url, isRead: $mode)
    }
}
